<?php
/**
 * BootAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using BootAdmin.
 *
 * @Author G.r<root@BootAdmin.com>
 */

declare (strict_types=1);

namespace app\common\service;

use think\facade\Filesystem;

/**
 * 文件鉴权类
 */
class File
{
    /**
     * 文件路径
     * @var string
     */
    protected string $path = '';

    /**
     * 相对路径
     * @var string
     */
    protected string $uri = '';

    /**
     * 缓存有效期
     * @var int
     */
    protected int $expire = 180;

    /**
     * 是否强制下载
     * @var bool
     */
    protected bool $force = false;

    /**
     * 文件类型
     * @var string
     */
    protected string $mimeType = '';

    /**
     * 是否为缩略图
     * @var bool
     */
    protected bool $suffix = false;

    /**
     * 缩略图背景
     * @var string
     */
    protected string $background = '';

    /**
     * 文件名
     * @var string
     */
    protected string $name = '';

    /**
     * 构建类
     * @param string $path 文件路径
     * @param bool $suffix 是否为缩略图
     * @param string $background 缩略图背景
     * @param bool $force 强制下载
     */
    public function __construct(string $path, bool $suffix = false, string $background = '', bool $force = false)
    {
        $this->path = $path;
        $this->force = $force;
        $this->suffix = $suffix;
        $this->background = $background;
        $this->getPathUrl();
    }

    /**
     * 输出文件
     */
    public function output()
    {
        $expires = gmdate("D, d M Y H:i:s", time() + $this->expire) . ' GMT';
        $modified = gmdate('D, d M Y H:i:s', time()) . ' GMT';
        if ($this->suffix) {
            $content    = build_suffix_svg((string)get_file_ext($this->path), $this->background);
            $size = strlen($content);
            header('Pragma:public;');
            header("Cache-control:max-age={$this->expire};");
            header("Content-Length:{$size};");
            header("Content-Transfer-Encoding:binary;");
            header("Expires:{$expires};");
            header("Last-Modified:{$modified};");
            header('Content-Type:image/svg+xml;');
            exit($content);
        }
        // 获取mime
        $mimeType = $this->getMimeType();
        $size     = filesize($this->path);
        // 设置Header
        header('Pragma:public;');
        header("Cache-control:max-age={$this->expire};");
        header("Content-Length:{$size};");
        header("Content-Transfer-Encoding:binary;");
        header("Expires:{$expires};");
        header("Last-Modified:{$modified};");
        if ($mimeType) {
            header("Content-Type:{$mimeType};");
        } else {
            header('Content-Type:application/octet-stream;');
        }
        if (!empty($this->name)) {
            $name = $this->name;
        } else {
            $name = pathinfo($this->path, PATHINFO_BASENAME);
        }
        // 强制下载
        if ($this->force) {
            header('Content-Disposition:attachment; filename="' . $name . '"');
        } else {
            header('Content-Disposition:filename="' . $name . '"');
        }
        header('X-Accel-Redirect: ' . $this->uri);
        exit();
    }

    /**
     * 设置有效期
     * @param  integer $expire 有效期
     * @return $this
     */
    public function expire(int $expire): static
    {
        $this->expire = $expire;
        return $this;
    }

    /**
     * 获取绝对路径
     */
    public function getPathUrl(): static
    {
        $this->uri  = str_replace("/",DIRECTORY_SEPARATOR, Filesystem::disk('public')->url($this->path));
        $this->path = str_replace("/",DIRECTORY_SEPARATOR, Filesystem::disk('public')->path($this->path));
        return $this;
    }

    /**
     * 获取文件类型
     */
    public function getMimeType(): bool|string
    {
        if (!empty($this->mimeType)) {
            return $this->mimeType;
        }

        $finfo = finfo_open(FILEINFO_MIME_TYPE);

        return finfo_file($finfo, $this->path);
    }

    /**
     * 设置下载文件的显示名称
     * @param  string $filename 文件名
     * @param  bool   $extension 后缀自动识别
     * @return $this
     */
    public function name(string $filename, bool $extension = true): static
    {
        $this->name = $filename;

        if ($extension && !str_contains($filename, '.')) {
            $this->name .= '.' . pathinfo($this->path, PATHINFO_EXTENSION);
        }

        return $this;
    }
}